#include "../include/Buffer.h"
#include "../include/Common.h"

void test_basic_construction()
{
    Buffer buf;
    assert(buf.ReadableSpace() == 0);
    assert(buf.getPrevSpace() == 0);
    assert(buf.getTailSpace() == 1024);
    std::cout << "✓ Basic construction test passed\n";
}

void test_write_and_read()
{
    Buffer buf;
    const char *data = "Hello, World!";
    size_t len = strlen(data);

    buf.WriteAndPush(data, len);
    assert(buf.ReadableSpace() == len);
    assert(buf.getPrevSpace() == 0);

    char read_buf[100];
    buf.ReadAndPop(read_buf, len);
    read_buf[len] = '\0';
    assert(strcmp(read_buf, data) == 0);
    assert(buf.ReadableSpace() == 0);
    std::cout << "✓ Write and read test passed\n";
}

void test_string_operations()
{
    Buffer buf;
    std::string test_str = "Test string";

    buf.WriteStringAndPush(test_str);
    assert(buf.ReadableSpace() == test_str.length());

    std::string read_str = buf.ReadAsStringAndPop(test_str.length());
    assert(read_str == test_str);
    std::cout << "✓ String operations test passed\n";
}

void test_buffer_to_buffer()
{
    Buffer buf1, buf2;
    std::string data = "Buffer to buffer test";

    buf1.WriteStringAndPush(data);
    buf2.WriteBufferAndPush(buf1);

    assert(buf2.ReadableSpace() == data.length());
    std::string result = buf2.ReadAsStringAndPop(data.length());
    assert(result == data);
    std::cout << "✓ Buffer to buffer test passed\n";
}

void test_line_operations()
{
    Buffer buf;
    std::string line1 = "First line\n";
    std::string line2 = "Second line\n";
    std::string line3 = "Third line without newline";

    buf.WriteStringAndPush(line1);
    buf.WriteStringAndPush(line2);
    buf.WriteStringAndPush(line3);

    std::string read_line1 = buf.GetLineAndPop();
    assert(read_line1 == line1);

    std::string read_line2 = buf.GetLineAndPop();
    assert(read_line2 == line2);

    std::string no_newline = buf.GetLine();
    assert(no_newline.empty());
    std::cout << "✓ Line operations test passed\n";
}

void test_space_management()
{
    Buffer buf;

    std::string data1(500, 'A');
    buf.WriteStringAndPush(data1);

    std::string partial = buf.ReadAsStringAndPop(250);
    assert(buf.ReadableSpace() == 250);
    assert(buf.getPrevSpace() == 250);

    std::string data2(800, 'B');
    buf.WriteStringAndPush(data2);

    assert(buf.ReadableSpace() == 250 + 800);
    std::cout << "✓ Space management test passed\n";
}

void test_expansion()
{
    Buffer buf;
    std::string large_data(2000, 'X');
    buf.WriteStringAndPush(large_data);

    assert(buf.ReadableSpace() == 2000);
    std::string result = buf.ReadAsStringAndPop(2000);
    assert(result == large_data);
    std::cout << "✓ Buffer expansion test passed\n";
}

void test_clear()
{
    Buffer buf;
    buf.WriteStringAndPush("test data");
    buf.clear();

    assert(buf.ReadableSpace() == 0);
    assert(buf.getPrevSpace() == 0);
    std::cout << "✓ Clear test passed\n";
}

void test_edge_cases()
{
    Buffer buf;

    std::string empty_str = "";
    buf.WriteStringAndPush(empty_str);
    assert(buf.ReadableSpace() == 0);

    buf.WriteStringAndPush("test");
    buf.MoveReadOffset(4);
    assert(buf.ReadableSpace() == 0);

    std::string no_newline = "no newline here";
    buf.clear();
    buf.WriteStringAndPush(no_newline);
    assert(buf.FindCRLF() == nullptr);
    assert(buf.GetLine().empty());

    std::cout << "✓ Edge cases test passed\n";
}

void test_writeable_space_bug()
{
    Buffer buf;

    uint64_t initial_space = buf.getTailSpace();
    assert(initial_space == 1024);

    buf.WriteStringAndPush("test");
    uint64_t remaining = buf.getTailSpace();
    assert(remaining == 1024 - 4);
    std::cout << "✓ WriteableSpace calculation test passed\n";
}

int main()
{
    std::cout << "Running Buffer class tests...\n\n";

    try
    {
        test_basic_construction();
        test_write_and_read();
        test_string_operations();
        test_buffer_to_buffer();
        test_line_operations();
        test_space_management();
        test_expansion();
        test_clear();
        test_edge_cases();
        test_writeable_space_bug();

        std::cout << "\n🎉 All tests passed!\n";
    }
    catch (const std::exception &e)
    {
        std::cerr << "Test failed with exception: " << e.what() << std::endl;
        return 1;
    }
    catch (...)
    {
        std::cerr << "Test failed with unknown exception" << std::endl;
        return 1;
    }

    LOG(DBG, "hello, arg1: %d, arg2 : %d", 1, 2);
    return 0;
}